﻿//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Expenses;
using Expenses.ExpenseService;
using Windows.UI.Xaml;

namespace Expenses.ViewModels
{
    public class ChargesViewModel : ViewModelBase
    {
        #region Properties

        private int numberLT30Days = 0;
        public int NumberLT30Days
        {
            get
            { return numberLT30Days; }

            set
            {
                if (numberLT30Days == value)
                { return; }

                numberLT30Days = value;
                RaisePropertyChanged("NumberLT30Days");
            }
        }

        private decimal amountLT30Days = 0M;
        public decimal AmountLT30Days
        {
            get
            { return amountLT30Days; }

            set
            {
                if (amountLT30Days == value)
                { return; }

                amountLT30Days = value;
                RaisePropertyChanged("AmountLT30Days");
            }
        }

        private int number30To44Days = 0;
        public int Number30To44Days
        {
            get
            { return number30To44Days; }

            set
            {
                if (number30To44Days == value)
                { return; }

                number30To44Days = value;
                RaisePropertyChanged("Number30To44Days");
            }
        }

        private decimal amount30To44Days = 0M;
        public decimal Amount30To44Days
        {
            get
            { return amount30To44Days; }

            set
            {
                if (amount30To44Days == value)
                { return; }

                amount30To44Days = value;
                RaisePropertyChanged("Amount30To44Days");
            }
        }

        private int numberGT45Days = 0;
        public int NumberGT45Days
        {
            get
            { return numberGT45Days; }

            set
            {
                if (numberGT45Days == value)
                { return; }

                numberGT45Days = value;
                RaisePropertyChanged("NumberGT45Days");
            }
        }

        private decimal amountGT45Days = 0M;
        public decimal AmountGT45Days
        {
            get
            { return amountGT45Days; }

            set
            {
                if (amountGT45Days == value)
                { return; }

                amountGT45Days = value;
                RaisePropertyChanged("AmountGT45Days");
            }
        }

        private DateTime beginDate;
        public DateTime BeginDate
        {
            get
            { return beginDate; }

            set
            {
                if (beginDate == value)
                { return; }

                beginDate = value;
                RaisePropertyChanged("BeginDate");
            }
        }

        private DateTime endDate;
        public DateTime EndDate
        {
            get
            { return endDate; }

            set
            {
                if (endDate == value)
                { return; }

                endDate = value;
                RaisePropertyChanged("EndDate");
            }
        }

        public ObservableCollection<SortType> SortTypes { get; set; }

        public ObservableCollection<GroupInfoList<object>> GroupedCharges
        {
            get
            {
                return groupedCharges;
            }

            set
            {
                groupedCharges = value;
                RaisePropertyChanged("GroupedCharges");
            }
        }

        public ObservableCollection<ChargeViewModel> Charges
        {
            get
            {
                return charges;
            }

            set
            {
                charges = value;
                RaisePropertyChanged("Charges");
            }
        }

        public SortType SortType
        {
            get
            {
                return sortType;
            }

            set
            {
                if (sortType == value)
                {
                    return;
                }

                sortType = value;
                RaisePropertyChanged("SortType");

                //update the grouping because the sort/filter type changed
                GroupItems();
            }
        }

        #endregion

        private SortType sortType = SortType.ItemType;
        private ObservableCollection<GroupInfoList<object>> groupedCharges;
        private ObservableCollection<ChargeViewModel> charges;

        public ChargesViewModel()
        {
            this.GroupedCharges = new ObservableCollection<GroupInfoList<object>>();
            this.SortTypes = new ObservableCollection<SortType>();
            this.SortTypes.Add(SortType.Age);
            this.SortTypes.Add(SortType.Amount);
        }

        public async Task<ObservableCollection<ChargeViewModel>> GetCharges()
        {
            var expensesService = new ExpenseServiceClient();
            List<Charge> outstandingCharges = await
                 expensesService.GetOutstandingChargesAsync(App.EmployeeId);

            var charges = from charge in outstandingCharges
                          select new ChargeViewModel()
                          {
                              Id = charge.Id,
                              BilledAmount = charge.BilledAmount,
                              Description = charge.Description,
                              EmployeeId = charge.EmployeeId,
                              ExpenseDate = charge.ExpenseDate,
                              ExpenseType = charge.ExpenseType,
                              Merchant = charge.Merchant,
                              Location = charge.Location,
                              Category = System.Convert.ToInt32(charge.Category),
                              AccountNumber = System.Convert.ToInt32(charge.AccountNumber),
                              TransactionAmount = charge.TransactionAmount,
                              ReceiptRequired = System.Convert.ToBoolean(charge.ReceiptRequired),
                              Notes=charge.Notes,
                              IsLate = (DateTime.Today.Subtract(charge.ExpenseDate).Days >= 45)
                          };
            this.Charges = new ObservableCollection<ChargeViewModel>(charges);

            foreach (ChargeViewModel charge in this.Charges)
            {
                if (DateTime.Today.Subtract(charge.ExpenseDate).Days >= 45)
                {
                    charge.ForegroundColor = "#FFD33131";
                }
                else
                {
                    charge.ForegroundColor = "Black";
                }
            }

            this.NumberLT30Days = (from charge in charges
                                   where DateTime.Today.Subtract(charge.ExpenseDate).Days < 30
                                   select charge.BilledAmount).Count();
            this.AmountLT30Days = (from charge in charges
                                   where DateTime.Today.Subtract(charge.ExpenseDate).Days < 30
                                   select charge.BilledAmount).Sum();
            this.Number30To44Days = (from charge in charges
                                     where DateTime.Today.Subtract(charge.ExpenseDate).Days >= 30
                                           && DateTime.Today.Subtract(charge.ExpenseDate).Days < 45
                                     select charge.BilledAmount).Count();
            this.Amount30To44Days = (from charge in charges
                                     where DateTime.Today.Subtract(charge.ExpenseDate).Days >= 30
                                           && DateTime.Today.Subtract(charge.ExpenseDate).Days < 45
                                     select charge.BilledAmount).Sum();
            this.NumberGT45Days = (from charge in charges
                                   where DateTime.Today.Subtract(charge.ExpenseDate).Days >= 45
                                   select charge.BilledAmount).Count();
            this.AmountGT45Days = (from charge in charges
                                   where DateTime.Today.Subtract(charge.ExpenseDate).Days >= 45
                                   select charge.BilledAmount).Sum();

            if (charges.Count() > 0)
            {
                this.beginDate = (from charge in charges
                                  select charge.ExpenseDate).Min();

                this.endDate = (from charge in charges
                                select charge.ExpenseDate).Max();
            }

            return this.Charges;
        }

        public void GroupItems()
        {
            switch (this.SortType)
            {
                case SortType.Age:
                    GroupItemsByTypeAndAge();
                    break;
                case SortType.Amount:
                    GroupItemsByTypeAndAmount();
                    break;
                case SortType.Submitter:
                    GroupItemsBySubmitter();
                    break;
                case SortType.ItemType:
                    GroupItemsByTypeAndAge();
                    break;
                default:
                    break;
            }
        }

        internal GroupInfoList<object> GroupItemsBySubmitter()
        {
            var query = from item in Charges
                        orderby item.EmployeeId
                        group item by item.EmployeeId into g
                        select new
                        {
                            GroupName = g.Key,
                            Count = g.Count(),
                            Amount = g.Sum(e => e.TransactionAmount),
                            Items = g
                        };

            var groups = new GroupInfoList<object>();
            foreach (var group in query)
            {
                var items = new GroupInfoList<object>();
                items.Key = string.Format(
                    "{0} ({1:C})", group.GroupName, group.Amount);
                items.Amount = System.Convert.ToDecimal(group.Amount);
                foreach (object item in items)
                {
                    items.Add(item);
                }
                groups.Add(items);
            }

            return groups;
        }


        private void GroupItemsByTypeAndAge()
        {
        }

        private void GroupItemsByTypeAndAmount()
        {
        }

    }
}
